/* This code is restricted under LGPL license */
using System;
using System.Collections.Generic;
using System.Reflection;
using NHibernate.Criterion;
using System.Collections;

namespace infoMECHANICA.NHibernateORM.CriteriaBuilder
{
    /// <summary>
    /// Property convertible into NHibernate criterions
    /// </summary>
    /// <typeparam name="T">Base property type</typeparam>
    public class CriterionProperty<T> : CriterionPropertyBase<T>, ICriterionProperty<T>
    {
        private CriterionJoin<T> passedByCriterionJoin;
        private ICriteriaRecorder parentRecorder;

        /// <summary>
        /// The instance of the object to which this criterion property belongs to
        /// </summary>
        protected ICriteriaRecorder ParentRecorder
        {
            get { return parentRecorder; }
            set { parentRecorder = value; }
        }

        /// <summary>
        /// Keeps join information between left and right criterions
        /// </summary>
        protected CriterionJoin<T> PassedByCriterionJoin
        {
            get { return passedByCriterionJoin; }
            set { passedByCriterionJoin = value; }
        }

        /// <summary>
        /// Passes criterion join
        /// </summary>
        /// <param name="value">Value to save</param>
        /// <returns>Internal criterion property</returns>
        private ICriterionJoin<T> PassBy(ICriterion value)
        {   
            this.SavedCriterion = value;
            ICriteriaRecorder recorderToMark = this.ParentRecorder;
            while (recorderToMark != null)
            {
                recorderToMark.HasSubreference = true;
                recorderToMark = recorderToMark.GetParent();
            }
            
            this.PassedByCriterionJoin = new CriterionJoin<T>(this.PropertyName);

            return this.PassedByCriterionJoin;
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public Order AsOrderAsc()
        {
            return Order.Asc(this.PropertyName);            
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public Order AsOrderDesc()
        {
            return Order.Desc(this.PropertyName);
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetBetween(T beginValue, T endValue)
        {
            ICriterion criterionToPass = Restrictions.Between(this.PropertyName, beginValue, endValue);
            return PassBy(criterionToPass);
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetEq(T value)
        {
            ICriterion criterionToPass = Restrictions.Eq(this.PropertyName, value);
            return PassBy(criterionToPass);
        }        

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetNotEq(T value)
        {
            ICriterion criterionToPass = Restrictions.Not(Restrictions.Eq(this.PropertyName, value));
            return PassBy(criterionToPass);
        }


        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetGe(T value)
        {
            ICriterion criterionToPass = Restrictions.Ge(this.PropertyName, value);
            return PassBy(criterionToPass);
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetGt(T value)
        {
            ICriterion criterionToPass = Restrictions.Gt(this.PropertyName, value);
            return PassBy(criterionToPass);
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetLt(T value)
        {
            ICriterion criterionToPass = Restrictions.Lt(this.PropertyName, value);
            return PassBy(criterionToPass);
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetLe(T value)
        {
            ICriterion criterionToPass = Restrictions.Le(this.PropertyName, value);
            return PassBy(criterionToPass);
        }
 
        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetIsEmpty()
        {
            ICriterion criterionToPass = Restrictions.IsEmpty(this.PropertyName);
            return PassBy(criterionToPass);
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetIsNotEmpty()
        {
            ICriterion criterionToPass = Restrictions.IsNotEmpty(this.PropertyName);
            return PassBy(criterionToPass);
        }

                /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetIsNull()
        {
            ICriterion criterionToPass = Restrictions.IsEmpty(this.PropertyName);
            return PassBy(criterionToPass);
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetIsNotNull()
        {
            ICriterion criterionToPass = Restrictions.IsNotNull(this.PropertyName);
            return PassBy(criterionToPass);
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetInsentiveLike(T value)
        {
            ICriterion criterionToPass = Restrictions.Like(this.PropertyName, value);
            return PassBy(criterionToPass);

        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetLike(T value)
        {
            ICriterion criterionToPass = Restrictions.Like(this.PropertyName, value);
            return PassBy(criterionToPass);

        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetIn(ICollection<T> values)
        {
            ICriterion criterionToPass = Restrictions.In(this.PropertyName, (ICollection) values);
            return PassBy(criterionToPass);
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetNotIn(ICollection<T> values)
        {
            ICriterion criterionToPass = Restrictions.Not(Restrictions.In(this.PropertyName, (ICollection)values));
            return PassBy(criterionToPass);
        }

        
        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetEq(GenericSubqueryProjection<T> subqueryProjection)
        {
            return SetEq(subqueryProjection.ToObjectSubqueryProjection());
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetEq(GenericSubqueryProjection<object> subqueryProjection)
        {            
            ICriterion criterionToPass = Subqueries.PropertyEq(this.PropertyName, subqueryProjection.ProjectedCriteria);
            return PassBy(criterionToPass);
        }


        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetEqAll(GenericSubqueryProjection<T> subqueryProjection)
        {
            return SetEqAll(subqueryProjection.ToObjectSubqueryProjection());
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetEqAll(GenericSubqueryProjection<object> subqueryProjection)
        {
            ICriterion criterionToPass = Subqueries.PropertyEqAll(this.PropertyName, subqueryProjection.ProjectedCriteria);
            return PassBy(criterionToPass);
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetGe(GenericSubqueryProjection<T> subqueryProjection)
        {
            return SetGe(subqueryProjection.ToObjectSubqueryProjection());
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetGe(GenericSubqueryProjection<object> subqueryProjection)
        {
            ICriterion criterionToPass = Subqueries.PropertyGe(this.PropertyName, subqueryProjection.ProjectedCriteria);
            return PassBy(criterionToPass);
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetGeAll(GenericSubqueryProjection<T> subqueryProjection)
        {
            return SetGeAll(subqueryProjection.ToObjectSubqueryProjection());
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetGeAll(GenericSubqueryProjection<object> subqueryProjection)
        {
            ICriterion criterionToPass = Subqueries.PropertyGeAll(this.PropertyName, subqueryProjection.ProjectedCriteria);
            return PassBy(criterionToPass);
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetGeSome(GenericSubqueryProjection<T> subqueryProjection)
        {
            return SetGeSome(subqueryProjection.ToObjectSubqueryProjection());
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetGeSome(GenericSubqueryProjection<object> subqueryProjection)
        {
            ICriterion criterionToPass = Subqueries.PropertyGeSome(this.PropertyName, subqueryProjection.ProjectedCriteria);
            return PassBy(criterionToPass);
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetGt(GenericSubqueryProjection<T> subqueryProjection)
        {
            return SetGt(subqueryProjection.ToObjectSubqueryProjection());
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetGt(GenericSubqueryProjection<object> subqueryProjection)
        {
            ICriterion criterionToPass = Subqueries.PropertyGt(this.PropertyName, subqueryProjection.ProjectedCriteria);
            return PassBy(criterionToPass);
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetGtAll(GenericSubqueryProjection<T> subqueryProjection)
        {
            return SetGtAll(subqueryProjection.ToObjectSubqueryProjection());
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetGtAll(GenericSubqueryProjection<object> subqueryProjection)
        {
            ICriterion criterionToPass = Subqueries.PropertyGtAll(this.PropertyName, subqueryProjection.ProjectedCriteria);
            return PassBy(criterionToPass);
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetGtSome(GenericSubqueryProjection<T> subqueryProjection)
        {
            return SetGtSome(subqueryProjection.ToObjectSubqueryProjection());
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetGtSome(GenericSubqueryProjection<object> subqueryProjection)
        {
            ICriterion criterionToPass = Subqueries.PropertyGtSome(this.PropertyName, subqueryProjection.ProjectedCriteria);
            return PassBy(criterionToPass);
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetIn(GenericSubqueryProjection<T> subqueryProjection)
        {
            return SetIn(subqueryProjection.ToObjectSubqueryProjection());
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetIn(GenericSubqueryProjection<object> subqueryProjection)
        {
            ICriterion criterionToPass = Subqueries.PropertyIn(this.PropertyName, subqueryProjection.ProjectedCriteria);
            return PassBy(criterionToPass);
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetLe(GenericSubqueryProjection<T> subqueryProjection)
        {
            return SetLe(subqueryProjection.ToObjectSubqueryProjection());
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetLe(GenericSubqueryProjection<object> subqueryProjection)
        {
            ICriterion criterionToPass = Subqueries.PropertyLe(this.PropertyName, subqueryProjection.ProjectedCriteria);
            return PassBy(criterionToPass);
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetLeAll(GenericSubqueryProjection<T> subqueryProjection)
        {
            return SetLeAll(subqueryProjection.ToObjectSubqueryProjection());
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetLeAll(GenericSubqueryProjection<object> subqueryProjection)
        {
            ICriterion criterionToPass = Subqueries.PropertyLeAll(this.PropertyName, subqueryProjection.ProjectedCriteria);
            return PassBy(criterionToPass);
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetLeSome(GenericSubqueryProjection<T> subqueryProjection)
        {
            return SetLeSome(subqueryProjection.ToObjectSubqueryProjection());
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetLeSome(GenericSubqueryProjection<object> subqueryProjection)
        {
            ICriterion criterionToPass = Subqueries.PropertyLeSome(this.PropertyName, subqueryProjection.ProjectedCriteria);
            return PassBy(criterionToPass);
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetLt(GenericSubqueryProjection<T> subqueryProjection)
        {
            return SetLt(subqueryProjection.ToObjectSubqueryProjection());
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetLt(GenericSubqueryProjection<object> subqueryProjection)
        {
            ICriterion criterionToPass = Subqueries.PropertyLt(this.PropertyName, subqueryProjection.ProjectedCriteria);
            return PassBy(criterionToPass);
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetLtAll(GenericSubqueryProjection<T> subqueryProjection)
        {
            return SetLtAll(subqueryProjection.ToObjectSubqueryProjection());
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetLtAll(GenericSubqueryProjection<object> subqueryProjection)
        {
            ICriterion criterionToPass = Subqueries.PropertyLtAll(this.PropertyName, subqueryProjection.ProjectedCriteria);
            return PassBy(criterionToPass);
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetLtSome(GenericSubqueryProjection<T> subqueryProjection)
        {
            return SetLtSome(subqueryProjection.ToObjectSubqueryProjection());
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetLtSome(GenericSubqueryProjection<object> subqueryProjection)
        {
            ICriterion criterionToPass = Subqueries.PropertyLtSome(this.PropertyName, subqueryProjection.ProjectedCriteria);
            return PassBy(criterionToPass);
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetNe(GenericSubqueryProjection<T> subqueryProjection)
        {
            return SetNe(subqueryProjection.ToObjectSubqueryProjection());
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetNe(GenericSubqueryProjection<object> subqueryProjection)
        {
            ICriterion criterionToPass = Subqueries.PropertyNe(this.PropertyName, subqueryProjection.ProjectedCriteria);
            return PassBy(criterionToPass);
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetNotIn(GenericSubqueryProjection<T> subqueryProjection)
        {
            return SetNotIn(subqueryProjection.ToObjectSubqueryProjection());
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterionJoin<T> SetNotIn(GenericSubqueryProjection<object> subqueryProjection)
        {
            ICriterion criterionToPass = Subqueries.PropertyNotIn(this.PropertyName, subqueryProjection.ProjectedCriteria);
            return PassBy(criterionToPass);
        }


        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterion AsEqCriterion(T value)
        {
            return Restrictions.Eq(this.PropertyName, value);
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterion AsNotEqCriterion(T value)
        {
            return Restrictions.Not(Restrictions.Eq(this.PropertyName, value));
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterion AsBetweenCriterion(T beginValue, T endValue)
        {
            return Restrictions.Between(this.PropertyName, beginValue, endValue);
        }


        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterion AsLtCriterion(T value)
        {
            return Restrictions.Lt(this.PropertyName, value);
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterion AsGtCriterion(T value)
        {
            return Restrictions.Gt(this.PropertyName, value);
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterion AsInCriterion(ICollection<T> value)
        {

            return Restrictions.InG(this.PropertyName, value);
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterion AsGeCriterion(T value)
        {
            return Restrictions.Ge(this.PropertyName, value);
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterion AsInsensitiveLikeCriterion(T value)
        {
            return Restrictions.InsensitiveLike(this.PropertyName, value);
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterion AsIsEmptyCriterion()
        {
            return Restrictions.IsEmpty(this.PropertyName);
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterion AsIsNotEmptyCriterion()
        {
            return Restrictions.IsNotEmpty(this.PropertyName);
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterion AsIsNullCriterion()
        {
            return Restrictions.IsNull(this.PropertyName);
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterion AsIsNotNullCriterion()
        {
            return Restrictions.IsNotNull(this.PropertyName);
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterion AsLeCriterion(T value)
        {
            return Restrictions.Le(this.PropertyName, value);
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public ICriterion AsLikeCriterion(T value)
        {
            return Restrictions.Like(this.PropertyName, value);
        }



        /// <summary>
        /// Gets left (primary) criterion - directly from this criterion property
        /// </summary>        
        private ICriterion GetLeftCriterion()
        {
            return this.SavedCriterion;

            //return base.ConvertToCriterion();
        }

        /// <summary>
        /// Gets right (secondary) criterion - from criterion join and internal criterion property
        /// </summary>
        /// <returns></returns>
        private ICriterion GetRightCriterion()
        {
            if (this.PassedByCriterionJoin != null)
            {
                return this.PassedByCriterionJoin.GetCriterion();
            }

            return null;
        }

        /// <summary>
        /// <see>ICriterionSource</see> interface summary
        /// </summary>
        public override ICriterion GetCriterion()
        {
            ICriterion leftCriterion = this.GetLeftCriterion();
            ICriterion rightCriterion = this.GetRightCriterion();

            if (this.SavedCriterion != null)
            {
                switch (this.PassedByCriterionJoin.CriterionJoinType)
                {
                    case CriterionJoinTypes.And:
                        if (rightCriterion != null)
                        {
                            return Restrictions.And(leftCriterion, rightCriterion);
                        }

                        return leftCriterion;

                    case CriterionJoinTypes.Or:
                        if (rightCriterion != null)
                        {
                            return Restrictions.Or(leftCriterion, rightCriterion);
                        }

                        return leftCriterion;


                    default: //CombinedCriterionTypes.None:
                        return leftCriterion;
                }
            }

            // only constructor was called - no criterions selected
            return null;
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public GenericSubqueryProjection<T> RecordedProjection
        {
            get
            {
                GenericSubqueryProjection<T> result = new GenericSubqueryProjection<T>(
                    this.ParentRecorder.BuildCriteria(), this.PropertyName, SubqueryProjectionTypes.Property);

                return result;
            }
        }

        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public GenericSubqueryProjection<T> RecordedProjectionMax
        {
            get
            {
                GenericSubqueryProjection<T> result = new GenericSubqueryProjection<T>(
                    this.ParentRecorder.BuildCriteria(), this.PropertyName, SubqueryProjectionTypes.Max);

                return result;
            }
        }
        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public GenericSubqueryProjection<T> RecordedProjectionMin
        {
            get
            {
                GenericSubqueryProjection<T> result = new GenericSubqueryProjection<T>(
                    this.ParentRecorder.BuildCriteria(), this.PropertyName, SubqueryProjectionTypes.Min);

                return result;
            }
        }
        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public GenericSubqueryProjection<T> RecordedProjectionAvg
        {
            get
            {
                GenericSubqueryProjection<T> result = new GenericSubqueryProjection<T>(
                    this.ParentRecorder.BuildCriteria(), this.PropertyName, SubqueryProjectionTypes.Avg);

                return result;
            }
        }
        /// <summary>
        /// <see>ICriterionProperty</see> interface summary
        /// </summary>
        public GenericSubqueryProjection<T> RecordedProjectionSum
        {
            get
            {
                GenericSubqueryProjection<T> result = new GenericSubqueryProjection<T>(
                    this.ParentRecorder.BuildCriteria(), this.PropertyName, SubqueryProjectionTypes.Sum);

                return result;
            }
        }

        
        /// <summary>
        /// Constructor, sets PropertyName
        /// </summary>
        /// <param name="propertyName">PropertyName to set</param>
        /// <param name="parent">The instance of recorder (parent object to this criteria property)</param>
        public CriterionProperty(string propertyName, ICriteriaRecorder parent) : base(propertyName)
        {
            this.ParentRecorder = parent;
        }




        #region IMergeablePropertySource Members

        /// <summary>
        /// Merges property value with another criterion property
        /// </summary>
        /// <param name="mergeSource">Source-merging property</param>
        public void Merge(object mergeSource)
        {
            if (mergeSource is CriterionProperty<T>)
            {
                this.SavedCriterion = ((CriterionProperty<T>)mergeSource).SavedCriterion;
                this.PassedByCriterionJoin = ((CriterionProperty<T>)mergeSource).PassedByCriterionJoin;                
            }
            else
            {
                throw new TargetException(String.Format(
                    "Invalid type of merged property: {0}. Invalid type: {1}, should be {2}",
                    this.PropertyName,
                    mergeSource.GetType().FullName,
                    this.GetType().FullName));
            }
        }

        #endregion
    }
}
